package com.example.adms.user.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.adms.common.excel.UserExcelData;
import com.example.adms.common.excel.UserExcelDataListener;
import com.example.adms.common.exception.ErrorVerifyException;
import com.example.adms.common.mail.Mail;
import com.example.adms.common.mail.MailProducer;
import com.example.adms.common.mail.MailService;
import com.example.adms.depart.entity.Depart;
import com.example.adms.depart.service.DepartService;
import com.example.adms.role.entity.Role;
import com.example.adms.role.service.RoleService;
import com.example.adms.user.dto.ChangeParams;
import com.example.adms.user.dto.LoginParams;
import com.example.adms.user.dto.PageParams;
import com.example.adms.user.entity.User;
import com.example.adms.user.mapper.UserMapper;
import com.example.adms.user.service.UserService;
import com.example.adms.user.vo.DepartLeaderVo;
import com.example.adms.vo.Result;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    //验证码
    @Autowired
    private DefaultKaptcha kaptcha;
    //redis
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private MailProducer mailProducer;

    @Autowired
    private DepartService departService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserMapper userMapper;

    //头像上传路径
    @Value("${system.imageUrl}")
    private String imageUrl;

    //邮件发送人
    @Value("${mail.sender}")
    private String mailSender;
    /**
     * 登录
     * @param loginParams
     * @return
     */
    @Override
    public Result login(LoginParams loginParams) {
        String vcode = redisTemplate.opsForValue().get("vcode");
        if (vcode != null && !vcode.equals(loginParams.getVcode())){
            return Result.fail(500,"验证码错误");
        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserId,loginParams.getUserId());
        //将输入的密码加密后再比较
        String md5Pwd = DigestUtils.md5DigestAsHex(loginParams.getPassword().getBytes());
        queryWrapper.eq(User::getPassword,md5Pwd);
        User user = this.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(user)){
            return Result.fail(500,"用户名或密码错误");
        }

        //登录成功，生成token
        StpUtil.login(user.getId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        String token = tokenInfo.getTokenValue();
        StpUtil.getSession().set("user",user);
        // 将token存入redis，设置过期时间为1天
        redisTemplate.opsForValue().set("Authorization:login:token:"+token, JSON.toJSONString(user),1, TimeUnit.DAYS);
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("id",user.getId());
        map.put("userId",user.getUserId());
        map.put("imageUrl",user.getImageUrl());
        return Result.success(map);
    }

    /**
     * 删除redis中存储的相关信息
     * @param token
     * @return
     */
    @Override
    public Result logout(String token) {
        StpUtil.logout();
        return Result.success(null);
    }

    /**
     * 根据id查用户
     * @param id
     * @return
     */
    @Override
    public Result getUserById(Integer id) {
        User user = this.getById(id);
        Map<String,Object> map = new HashMap<>();
        map.put("user",user);
        return Result.success(map);
    }

    /**
     * 生成验证码
     * @return
     */
    @Override
    public Result getVcode() {
        String text = kaptcha.createText();//生成文本
        redisTemplate.opsForValue().set("vcode",text,180, TimeUnit.SECONDS);//存入redis

        //生成图片
        BufferedImage image = kaptcha.createImage(text);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        try {
            ImageIO.write(image,"jpg",bos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String base64Code = "data:image/jpeg;base64,"+ Base64Utils.encodeToString(bos.toByteArray());
        Map<String,Object> map = new HashMap<>();
        map.put("imageCode",base64Code);
        return Result.success(map);
    }

    /**
     * 根据用户名查
     * @return
     */
    @Override
    public Result getByUserId(String userId) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUserId,userId);
        Map<String,Object> map = new HashMap<>();
        map.put("user",this.getOne(queryWrapper));
        return Result.success(map);
    }

    /**
     * 添加、修改用户
     * @param user
     * @return
     */
    @Override
    public Result addOrUpdateUser(User user) {
        String password = user.getPassword();
        //密码加密
        String md5Pwd = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setPassword(md5Pwd);
        boolean flag = false;
        if (user.getId() != null){
            //有id说明是修改
            flag = this.updateById(user);
        } else {
            //无id说明是添加
            flag = this.save(user);
        }
        if (flag){
            return Result.success(null);
        } else {
            return Result.fail(500,"操作失败");
        }
    }

    /**
     * 头像上传
     * @param file
     * @return
     */
    @Override
    public Result imageUpload(MultipartFile file) {
        String destPath = imageUrl+"/"+file.getOriginalFilename();
        File destFile = new File(destPath);
        try {
            file.transferTo(destFile);
            return Result.success(null);
        } catch (IOException e) {
            e.printStackTrace();
            return Result.fail(500,"头像上传失败");
        }
    }

    /**
     * 根据id删除用户
     * @param id
     * @return
     */
    @Override
    public Result delUserById(Integer id) {
        boolean flag = this.removeById(id);
        if (flag){
            return Result.success(null);
        } else {
            return Result.fail(500,"删除失败");
        }
    }

    /**
     * 分页查用户列表
     * @param pageParams
     * @return
     */
    @Override
    public Result getUserList(PageParams pageParams) {
        Page<User> page = new Page<>(pageParams.getPageNumber(), pageParams.getPageSize());
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(pageParams.getUserId() != null,User::getUserId,pageParams.getUserId());
        queryWrapper.eq(pageParams.getRoleId() != null,User::getRoleId,pageParams.getRoleId());
        queryWrapper.eq(pageParams.getDepartId() != null,User::getDepartId,pageParams.getDepartId());
        Page<User> userPage = this.page(page, queryWrapper);
        List<User> users = userPage.getRecords();
        long total = userPage.getTotal();
        Map<String,Object> map = new HashMap<>();
        map.put("userList",users);
        map.put("total",total);
        return Result.success(map);
    }

    /**
     * 发送邮件
     * @return
     */
    @Override
    public Result sendMail(String mailTo) {
        User user = (User) StpUtil.getSession().get("user");
        String text = kaptcha.createText();//生成文本
        redisTemplate.opsForValue().set("changeVcode:"+user.getId(),text,180,TimeUnit.SECONDS);
//        mailService.sendSimpleMail(mailSender,
//                mail,
//                mailSender,
//                "密码修改验证码",
//                "你的验证码为"+text+",有效时间为180s");
        Mail mail = new Mail();
        mail.setTo(mailTo);
        mail.setSubject("密码修改验证码");
        mail.setContent("你的验证码为"+text+"有效时间180s");
        mailProducer.fireMail(mail);
        return Result.success(null);
    }

    /**
     * 密码修改
     * @param changeParams
     * @return
     */
    @Override
    public Result changePwd(ChangeParams changeParams) {
        String changeVcode = changeParams.getChangeVcode();
        String vcode = redisTemplate.opsForValue().get("changeVcode");
        if (!changeVcode.equals(vcode)){
            throw new ErrorVerifyException("验证码错误");
        }
        User user = new User();
        String md5Pwd = DigestUtils.md5DigestAsHex(changeParams.getPassword().getBytes());
        user.setPassword(md5Pwd);
        user.setId(changeParams.getId());
        boolean flag = this.updateById(user);
        if (flag){
            return Result.success(null);
        } else {
            return Result.fail(500,"修改失败");
        }
    }

    /**
     * 从上传的excel添加用户
     * @param file
     * @return
     */
    @Override
    public Result readUserFromExcel(MultipartFile file) {
        try {
            InputStream inputStream = file.getInputStream();
            EasyExcel.read(inputStream, UserExcelData.class,new UserExcelDataListener(this)).sheet().doRead();
        } catch (IOException e){
            e.printStackTrace();
            return Result.fail(500,"读取失败");
        }
        return Result.success(null);
    }

    /**
     * 根据从excel读取到的数据进行插入
     * @param list
     */
    @Override
    public void addUserByExcel(List<UserExcelData> list) {
        LambdaQueryWrapper<Depart> queryWrapperDepart = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Role> queryWrapperRole = new LambdaQueryWrapper<>();
        List<User> userList = new ArrayList<>();
        for (UserExcelData data : list){
            log.info("数据：{}",data);
            //根据部门名查部门id
            queryWrapperDepart.clear();//每次添加条件之前先移除
            queryWrapperDepart.eq(Depart::getDepartName,data.getDepartName());
            Depart depart = departService.getOne(queryWrapperDepart);
            //根据角色名查角色id
            queryWrapperRole.clear();//每次添加条件之前先移除
            queryWrapperRole.eq(Role::getRoleName,data.getRoleName());
            Role role = roleService.getOne(queryWrapperRole);

            User user = new User();
            BeanUtils.copyProperties(data,user);
            //密码加密
            String md5Pwd = DigestUtils.md5DigestAsHex(data.getPassword().getBytes());
            user.setPassword(md5Pwd);
            user.setDepartId(depart.getDepartId());
            user.setRoleId(role.getRoleId());
            //设置默认头像
            user.setImageUrl("http://localhost:9999/view/default.jpg");
            userList.add(user);
        }
        this.saveBatch(userList);
    }

    /**
     * 获取部门领导信息
     * @return
     */
    @Override
    public Result getDepartLeader() {
        List<DepartLeaderVo> list = userMapper.selectLeader();
        return Result.success(list);
    }
}
